// NO (INTER-)DEPENDENCIES!

/* List of all the "API" functions:
 * individualize(): see definition!
*/

/* ------------------------
| Compilation Necessities |
-------------------------*/

using namespace std;

#include <pcrecpp.h>
using namespace pcrecpp;

#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
using namespace boost;

// DECIDE ABOUT THIS MESS LATER (...)

#ifndef TYPICAL_STRINGS
#define TYPICAL_STRINGS
static const string blank( "" );
static const string date = "[0-9]{4}-[0-9]{2}-[0-9]{2}";
#endif

#ifndef PCRE_ICASE
#define PCRE_ICASE
// SQL being case-insensitive,
// our patterns must be too.
static const RE_Options icase( PCRE_CASELESS );
#endif

/* -----------------
| Code starts now! |
----------------- */

// Returned "unsigned" semantics:
// 0 = "PATTERNED", 1 = NECESSARY
// 2 = UNKNOWN, 3 = NOT NECESSARY
pair<unsigned,string> individualize( string& portion ){

	// Removal of these between "clauses" is somewhat
	// messy without removing nesting and fixing commas.
	static const regex nesting( "(\\(|\\)|\\s)+" );
	static const regex commas( "\\s*,\\s*" );
	static const regex between1( "(('"+date+"')|(S?#(\\w|#)+#N?))\\s+(NOT\\s+)?BETWEEN", regex::icase );
	static const regex between2( "\\b(NOT\\s+)?BETWEEN\\s+(((UNBOUNDED PRECEDING)|(\\d+)"
		"|('"+date+"')|(:START_DT)|(E#M#P#T#Y( -3)?)" // HACKY CHECKING!
		"|(\\w?#(\\w|#)+#\\w?)) AND ((UNBOUNDED FOLLOWING)|(E#M#P#T#Y( -3)?)"
		"|(\\d+)|('"+date+"')|(:END_DT)|(\\w?#(\\w|#)+#\\w?)))", regex::icase );

	portion = regex_replace( portion, nesting, " " );
	portion = regex_replace( portion, commas, ", " );
	trim( portion );
	portion = regex_replace( portion, between1, "" );
	portion = regex_replace( portion, between2, "" );

	static const RE sn( "^SELECT\\b", icase );
	static const RE ft( "^FROM\\b", icase );
	static const RE wc( "^WHERE\\b", icase );
	static const RE gr( "^GR#OUP#BY\\b", icase );
	static const RE ob( "^OR#DER#BY\\b", icase );
	static const RE jt( "^J#O#I#N#ON\\b", icase );

	if( sn.PartialMatch( portion ) ){

		// Aliases are to be retained for other portions,
		// hence removed (only) here, specifically...
		static const regex column_aliases( "\\b(AS)\\s+[^,\\s]+", regex::icase );
		static const regex commas( "\\s*,\\s*" );
		portion = regex_replace( portion, column_aliases, " " );
		portion = regex_replace( portion, commas, ", " );

		return make_pair( 1, string( "sn# " ) );

	}

	// Explicit aliases are not compulsory, hence it
	// is easier to remove the "AS" keyword entirely.
	static const regex explicit_alias( "\\b(AS)\\s+", regex::icase );
	portion = regex_replace( portion, explicit_alias, " " );
	portion = regex_replace( portion, commas, ", " );

	//if( ft.PartialMatch( portion ) )
		//return make_pair( 1, string( "ft# " ) );

	/*else*/ if( wc.PartialMatch( portion ) )
		return make_pair( 1, string( "wc# " ) );
	else if( gr.PartialMatch( portion ) )
		return make_pair( 1, string( "gr# " ) );
	else if( ob.PartialMatch( portion ) )
		return make_pair( 1, string( "ob# " ) );
	else if( jt.PartialMatch( portion ) )
		return make_pair( 1, string( "j2# " ) );

	return make_pair( 3, string( "ig# " ) );

}
